#pragma once
#include "fields.hpp"
#include "detail.hpp"
#include "abstract.hpp"

namespace myrpc
{
    class JsonMessage : public BaseMessage
    {
        public:
            using ptr=std::shared_ptr<JsonMessage>;
            virtual std::string serialize() override
            {
                std::string body;
                bool result=JSON::serialize(_body,body);
                if(result==false)
                {
                    ELOG("序列化失败！");
                    return std::string();
                }
                return body;
            }
            virtual bool unserialize(const std::string& msg) override
            {
                return JSON::unserialize(msg,_body);
            }
        protected:
            Json::Value _body;
    };
    class JsonRequest : public JsonMessage
    {
        public:
            using ptr=std::shared_ptr<JsonRequest>;

    };
    class JsonResponse : public JsonMessage
    {
        public:
            using ptr=std::shared_ptr<JsonResponse>;
        virtual bool check() override
        {
            //在响应中，大部分响应都只有响应状态码
            //因此我们只需要怕段响应状态码字段是否存在，类型是否正确
            if(_body[KEY_RCODE].isNull()==true)
            {
                ELOG("响应中没有响应状态码！");
                return false;
            }
            //判断响应状态码是否为整型
            if(_body[KEY_RCODE].isIntegral()==false)
            {
                ELOG("响应状态码类型错误！")
                return false;
            }
            return true;
        }
        virtual RCode rcode()
        {
            return (RCode)_body[KEY_RCODE].asInt();
        }
        virtual void setRcode(const RCode& rcode)
        {
            _body[KEY_RCODE]=(int)rcode;
        }        
    };

    //请求部分
    class RpcRequest : public JsonRequest
    {
        public:
            using ptr=std::shared_ptr<RpcRequest>;
            virtual bool check() override
            {
                //rpc请求中，包含请求方法名称（字符串），参数字段（对象Json::Value）
                if(_body[KEY_METHOD].isNull()==true || _body[KEY_METHOD].isString()==false)
                {
                    ELOG("RPC请求中没有请求方法或者方法名称类型错误！");
                    return false;
                }
                if(_body[KEY_PARAMS].isNull()==true || _body[KEY_PARAMS].isObject()==false)
                {
                    ELOG("RPC请求中没有参数信息或者参数信息类型错误！");
                    return false;
                }
                return true;
            }

            std::string method()
            {
                return _body[KEY_METHOD].asString();
            }
            void setMethod(const std::string &method_name)
            {
                _body[KEY_METHOD]=method_name;
            }
            
            Json::Value params()
            {
                return _body[KEY_PARAMS];
            }
            void setParams(const Json::Value &params)
            {
                _body[KEY_PARAMS]=params;
            }
    };
    class TopicRequest : public JsonRequest
    {
        public:
            using ptr=std::shared_ptr<TopicRequest>;
            virtual bool check() override
            {
                //主题请求中，包含主题名称、主题操作类型、如果是消息发布，需要检查消息字段
                if(_body[KEY_TOPIC_KEY].isNull()==true || _body[KEY_TOPIC_KEY].isString()==false)
                {
                    ELOG("主题请求中没有主题名称或者主题名称类型错误！");
                    return false;
                }
                if(_body[KEY_OPTYPE].isNull()==true || _body[KEY_OPTYPE].isIntegral()==false)
                {
                    ELOG("主题请求中没有操作类型或者操作类型的类型错误！");
                    return false;
                }
                //如果是主题操作类型如果是消息发布，检查消息字段是否为空和类型是否正确
                if(_body[KEY_OPTYPE].asInt()==(int)TopicOptype::TOPIC_PUBLISH && 
                (_body[KEY_TOPIC_MSG].isNull()==true || _body[KEY_TOPIC_MSG].isString()==false))
                {
                    ELOG("主题消息发布请求中没有消息内容字段或者消息内容字段类型错误！");
                    return false;                   
                }
                return true;
            }
            std::string topicKey()
            {
                return _body[KEY_TOPIC_KEY].asString();
            }
            void setTopicKey(const std::string &topicKey)
            {
                _body[KEY_TOPIC_KEY]=topicKey;
            }
            TopicOptype topicOptype()
            {
                return (TopicOptype)_body[KEY_OPTYPE].asInt();
            }
            void setTopicOptype(const TopicOptype &optype)
            {
                _body[KEY_OPTYPE]=(int)optype;
            }
            std::string topicMsg()
            {
                return _body[KEY_TOPIC_MSG].asString();
            }
            void setTopicMsg(const std::string &msg)
            {
                _body[KEY_TOPIC_MSG]=msg;
            }

    };

    typedef std::pair<std::string,int> Address;
    class ServiceRequest : public JsonRequest
    {
       public:
            using ptr=std::shared_ptr<ServiceRequest>;
            virtual bool check() override
            {
                //服务请求中，包含服务请求方法名称、服务操作类型、host主机信息（Json::Value）
                if(_body[KEY_METHOD].isNull()==true || _body[KEY_METHOD].isString()==false)
                {
                    ELOG("服务请求中没有服务请求方法或者服务请求方法类型错误！");
                    return false;
                }
                if(_body[KEY_OPTYPE].isNull()==true || _body[KEY_OPTYPE].isIntegral()==false)
                {
                    ELOG("服务请求中没有操作类型或者操作类型的类型错误！");
                    return false;
                }
                //服务发现的时候不需要主机信息
                if(_body[KEY_OPTYPE].asInt()!=(int)ServiceOptype::SERVICE_DISCOVER &&
                    (_body[KEY_HOST].isNull()==true || _body[KEY_HOST].isObject()==false ||
                    _body[KEY_HOST][KEY_HOST_IP].isNull()==true || _body[KEY_HOST][KEY_HOST_IP].isString()==false ||
                    _body[KEY_HOST][KEY_HOST_PORT].isNull()==true || _body[KEY_HOST][KEY_HOST_PORT].isInt()==false))
                {
                    ELOG("服务请求中主机地址信息错误！");
                    return false;
                }
                return true;
            }
            std::string method()
            {
                return _body[KEY_METHOD].asString();
            }
            void setMethod(const std::string &method)
            {
                _body[KEY_METHOD]=method;
            }
            ServiceOptype serviceOptype()
            {
                return (ServiceOptype )_body[KEY_OPTYPE].asInt();
            }
            void setServiceOptype(const ServiceOptype &optype)
            {
                _body[KEY_OPTYPE]=(int)optype;
            }
            Address host()
            {
                Address addr;
                addr.first=_body[KEY_HOST][KEY_HOST_IP].asString();
                addr.second=_body[KEY_HOST][KEY_HOST_PORT].asInt();
                return addr;
            }
            void setHost(const Address &host)
            {
                Json::Value val;
                val[KEY_HOST_IP]=host.first;
                val[KEY_HOST_PORT]=host.second;
                _body[KEY_HOST]=val;
            }

    };

    //响应部分
    class RpcResponse : public JsonResponse
    {
        public:
            using ptr=std::shared_ptr<RpcResponse>;
            //RPC响应中，包含响应状态码（整型-宏），响应结果（Json::Value）
            virtual bool check()
            {
                if(_body[KEY_RCODE].isNull()==true || _body[KEY_RCODE].isInt()==false)
                {
                    ELOG("RPC响应中没有响应状态码或者响应状态码类型错误！");
                    return false;
                }

                if(_body[KEY_RESULT].isNull()==true)
                {
                    ELOG("RPC响应中没有Rpc调用结果！")
                    return false;
                }
                return true;
            }


            Json::Value result()
            {
                return _body[KEY_RESULT];
            }
            void setResult(const Json::Value &result)
            {
                _body[KEY_RESULT]=result;
            }
    };
    class TopicResponse : public JsonResponse
    {
        public:
            using ptr=std::shared_ptr<TopicResponse>;
            //主题响应中，只需要检查下状态码即可

    };
    //如果是服务注册/上线/下线的响应，body只需要有响应状态码字段，而服务发现的话还需要一个host数组和method字段
    //通过optype字段区分是不是服务发现
    class ServiceResponse : public JsonResponse
    {
        public:
            using ptr=std::shared_ptr<ServiceResponse>;
            virtual bool check()
            {
                if(_body[KEY_RCODE].isNull()==true || _body[KEY_RCODE].isInt()==false)
                {
                    ELOG("响应中没有响应状态码或者响应状态码类型错误！");
                    return false;
                }
                if(_body[KEY_OPTYPE].isNull()==true || _body[KEY_OPTYPE].isInt()==false)
                {
                    ELOG("响应中没有操作类型，或者操作类型的类型错误");
                    return false;
                }

                if(_body[KEY_OPTYPE].asInt()==(int)ServiceOptype::SERVICE_DISCOVER && 
                  (_body[KEY_METHOD].isNull()==true || _body[KEY_METHOD].isString()==false)||
                   _body[KEY_HOST].isNull()==true || _body[KEY_HOST].isArray()==false)
                {
                    ELOG("服务发现响应中，响应信息字段错误！");
                    return false;
                }
                return true;
            }
            std::string method()
            {
                return _body[KEY_METHOD].asString();
            }
            void setMethod(const std::string &method)
            {
                _body[KEY_METHOD]=method;
            }
            ServiceOptype serviceOptype()
            {
                return (ServiceOptype)_body[KEY_OPTYPE].asInt();
            }
            void setServiceOptype(const ServiceOptype &optype)
            {
                _body[KEY_OPTYPE]=(int)optype;
            }
            void setHost(const Address& addr)
            {
                Json::Value val;
                val[KEY_HOST_IP]=addr.first;
                val[KEY_HOST_PORT]=addr.second;
                _body[KEY_HOST].append(val);
            }
            void setHost(const std::vector<Address>& addr)
            {
                for(int i=0;i<addr.size();i++)
                {
                    Json::Value val;
                    val[KEY_HOST_IP]=addr[i].first;
                    val[KEY_HOST_PORT]=addr[i].second;
                    _body[KEY_HOST].append(val);
                }
            }
            std::vector<Address> hosts()
            {
                std::vector<Address> addrs;
                int sz=_body[KEY_HOST].size();
                for(int i=0;i<sz;i++)
                {
                    Address addr;
                    addr.first=_body[KEY_HOST][i][KEY_HOST_IP].asString();
                    addr.second=_body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                    addrs.push_back(addr);
                }
                return addrs;
            }
    };

    //实现一个消息对象的生产工厂
    class MessageFactory
    {
        public:
            static BaseMessage::ptr create(MType mtype)
            {
                switch(mtype)
                {
                    case MType::REQ_RPC : return std::make_shared<RpcRequest>();
                    case MType::RSP_RPC : return std::make_shared<RpcResponse>();
                    case MType::REQ_TOPIC : return std::make_shared<TopicRequest>();
                    case MType::RSP_TOPIC : return std::make_shared<TopicResponse>();
                    case MType::REQ_SERVICE : return std::make_shared<ServiceRequest>();
                    case MType::RSP_SERVICE : return std::make_shared<ServiceResponse>();
                }
                return BaseMessage::ptr();
            };
            template<typename T,typename ...Args>
            static std::shared_ptr<T> create(Args&& ...args)
            {
                return std::make_shared<T>(std::forward(args)...);
            }
    };
}